"""
Copyright © 2023 Walkline Wang (https://walkline.wang)
Gitee: https://gitee.com/walkline/micropython-ws2812-led-clock
"""
import struct
from utime import sleep_ms
from micropython import const
from machine import SoftI2C, I2C, Pin


#region registers
REG_WHO_AM_I = const(0x0f)

REG_OUT_TEMP_L     = const(0x0c)
REG_OUT_TEMP_H     = const(0x0d)
REG_STATUS_REG_AUX = const(0x07)
REG_TEMP_CFG_REG   = const(0x1f)

REG_CTRL_REG0 = const(0x1e)
REG_CTRL_REG1 = const(0x20)
REG_CTRL_REG2 = const(0x21)
REG_CTRL_REG3 = const(0x22)
REG_CTRL_REG4 = const(0x23)
REG_CTRL_REG5 = const(0x24)
REG_CTRL_REG6 = const(0x25)

REG_REFERENCE = const(0x26)

REG_STATUS_REG = const(0x27)
REG_OUT_X_L    = const(0x28)
REG_OUT_X_H    = const(0x29)
REG_OUT_Y_L    = const(0x2a)
REG_OUT_Y_H    = const(0x2b)
REG_OUT_Z_L    = const(0x2c)
REG_OUT_Z_H    = const(0x2d)

REG_FIFO_CTRL_REG = const(0x2e)
REG_FIFO_SRC_REG  = const(0x2f)

REG_INT1_CFG = const(0x30)
REG_INT1_SRC = const(0x31)
REG_INT1_THS = const(0x32)
REG_INT1_DUR = const(0x33)

REG_INT2_CFG = const(0x34)
REG_INT2_SRC = const(0x35)
REG_INT2_THS = const(0x36)
REG_INT2_DUR = const(0x37)

REG_CLICK_CFG = const(0x38)
REG_CLICK_SRC = const(0x39)
REG_CLICK_THS = const(0x3a)

REG_TIME_LIMIT   = const(0x3b)
REG_TIME_LATENCY = const(0x3c)
REG_TIME_WINDOW  = const(0x3d)

REG_ACT_THS = const(0x3e)
REG_ACT_DUR = const(0x3f)


# 寄存器控制位

# == CTRL_REG0 ==
BIT_SDO_PU_DISC = 7

# == CTRL_REG1 ==
# BIT_ORD3 = 7
# BIT_ORD2 = 6
# BIT_ORD1 = 5
BIT_ORD0 = 4
BIT_LPEN = 3 # Low-power mode enable

# == CTRL_REG2 ==

# == CTRL_REG3 ==
BIT_I1_CLICK   = 7
BIT_I1_IA1     = 6
BIT_I1_IA2     = 5
BIT_I1_ZYXDA   = 4
BIT_I1_WTM     = 2
BIT_I1_OVERRUN = 1

# == CTRL_REG4 ==
BIT_BDU = 7 # Block Data Update
BIT_BLE = 6 # Big/Little Endian data selection
# BIT_FS1 = 5
BIT_FS0 = 4 # Full-scale configuration
BIT_HR  = 3 # Operating mode selection
BIT_SIM = 0 # SPI serial interface mode selection

# == CTRL_REG5 ==
BIT_BOOT = 7 # Reboot memory content

# == CTRL_REG6 ==
BIT_I2_CLICK     = 7
BIT_I2_IA1       = 6
BIT_I2_IA2       = 5
BIT_I2_BOOT      = 4
BIT_I2_ACT       = 3
BIT_INT_POLARITY = 1


# == CLICK_CFG ==
BIT_ZD = 5 # Enable interrupt double-click on Z-axis
BIT_ZS = 4 # Enable interrupt single-click on Z-axis
BIT_YD = 3 # Enable interrupt double-click on Y-axis
BIT_YS = 2 # Enable interrupt single-click on Y-axis
BIT_XD = 1 # Enable interrupt double-click on X-axis
BIT_XS = 0 # Enable interrupt single-click on X-axis

# == CLICK_THS ==
BIT_LIR_CLICK = 7
# BIT_THS6      = 6
BIT_THS0      = 0

# == CLICK_SRC ==
BIT_CLICK_IA = 6
BIT_DCLICK   = 5
BIT_SCLICK   = 4
BIT_SIGN     = 3
BIT_CLICK_Z  = 2
BIT_CLICK_Y  = 1
BIT_CLICK_X  = 0


# == TIME_LIMIT ==
# BIT_TLI6 = 6
BIT_TLI0 = 0

# == TIME_LATENCY ==
# == TIME_WINDOW ==


# == INT1_DURATION ==
BIT_D0 = 0

# == INT2_DURATION ==

# == INT1_THS ==
# BIT_THS0 = 0

# == INT1_THS ==

# == INT1_SRC ==
BIT_INT_IA = 6
BIT_ZH     = 5
BIT_ZL     = 4
BIT_YH     = 3
BIT_YL     = 2
BIT_XH     = 1
BIT_XL     = 0


# == STATUS_REG ==
BIT_ZYXOR = 7 # Info about device status
BIT_ZOR   = 6
BIT_YOR   = 5
BIT_XOR   = 4
BIT_ZYXDA = 3
BIT_ZDA   = 2
BIT_YDA   = 1
BIT_XDA   = 0

# == STATUS_REG_AUX ==
BIT_TOR = 6 # Temperature data available
BIT_TDA = 2 # Temperature data overrun
#endregion registers


PROPERTY_DISABLED = 0
PROPERTY_ENABLED  = 1

DOUBLE_CLICK = 0b101010
SINGLE_CLICK = 0b010101

MOVEMENT_6D  = 0b01111111
DIRECTION_6D = 0b11111111


class LIS2DH12LiteException(BaseException):
	pass


class LIS2DH12Lite(object):
	#region constants
	ID = const(0x33) # (Who am I)
	IIC_ADDRS = (
		0x18, # 001 1000 | connected to gnd
		0x19  # 001 1001 | connected to vcc
	)

	FULL_SCALE_2G  = 0b00
	FULL_SCALE_4G  = 0b01
	FULL_SCALE_8G  = 0b10
	FULL_SCALE_16G = 0b11

	MODE_NORMAL_10BIT   = 0b00
	MODE_HIGH_RES_12BIT = 0b01
	MODE_LOW_POWER_8BIT = 0b10

	ORD_POWER_DOWN          = 0B0000
	ORD_1HZ                 = 0B0001
	ORD_10HZ                = 0B0010
	ORD_25HZ                = 0B0011
	ORD_50HZ                = 0B0100
	ORD_100HZ               = 0B0101
	ORD_200HZ               = 0B0110
	ORD_400HZ               = 0B0111
	ORD_1620HZ_LP           = 0B1000
	ORD_5376HZ_LP_1344HZ_NM = 0B1001
	ORD_RANGES              = range(ORD_POWER_DOWN, ORD_5376HZ_LP_1344HZ_NM + 1)

	MODE_CLICK_SINGLE  = 0
	MODE_CLICK_DOUBLE  = 1
	MODE_CLICK_DISABLE = 2

	MODE_6D_MOVEMENT  = 0
	MODE_6D_DIRECTION = 1
	#endregion constants

	def __init__(self, i2c:SoftI2C=None, i2c_addr=IIC_ADDRS[1]):
		assert isinstance(i2c, (SoftI2C, I2C)), LIS2DH12LiteException('i2c is not I2C instance')
		assert i2c_addr in LIS2DH12Lite.IIC_ADDRS, LIS2DH12LiteException('invalid i2c address')

		self.__i2c = i2c
		self.__i2c_addr = i2c_addr

	def device_id(self):
		'''获取芯片 ID'''
		return self.__read_mem(REG_WHO_AM_I)[0]

	def reset(self):
		'''软复位寄存器数据'''
		sleep_ms(5)

		self.__write_mem(REG_CTRL_REG0,     0x10)
		self.__write_mem(REG_CTRL_REG1,     0x07)

		self.__write_mem(REG_CTRL_REG2, bytearray(5))
		# self.__write_mem(REG_CTRL_REG2,     0x00)
		# self.__write_mem(REG_CTRL_REG3,     0x00)
		# self.__write_mem(REG_CTRL_REG4,     0x00)
		# self.__write_mem(REG_CTRL_REG5,     0x00)
		# self.__write_mem(REG_CTRL_REG6,     0x00)

		self.__write_mem(REG_TEMP_CFG_REG,  0x00)
		self.__write_mem(REG_REFERENCE,     0x00)
		self.__write_mem(REG_FIFO_CTRL_REG, 0x00)

		self.__write_mem(REG_INT1_CFG,      0x00)

		self.__write_mem(REG_INT1_THS, bytearray(3))
		# self.__write_mem(REG_INT1_THS,      0x00)
		# self.__write_mem(REG_INT1_DUR,      0x00)
		# self.__write_mem(REG_INT2_CFG,      0x00)

		self.__write_mem(REG_INT2_THS, bytearray(3))
		# self.__write_mem(REG_INT2_THS,      0x00)
		# self.__write_mem(REG_INT2_DUR,      0x00)
		# self.__write_mem(REG_CLICK_CFG,     0x00)

		self.__write_mem(REG_CLICK_THS, bytearray(6))
		# self.__write_mem(REG_CLICK_THS,     0x00)
		# self.__write_mem(REG_TIME_LIMIT,    0x00)
		# self.__write_mem(REG_TIME_LATENCY,  0x00)
		# self.__write_mem(REG_TIME_WINDOW,   0x00)
		# self.__write_mem(REG_ACT_THS,       0x00)
		# self.__write_mem(REG_ACT_DUR,       0x00)


		# data = self.__read_mem(REG_CTRL_REG5)[0]
		# self.__write_mem(REG_CTRL_REG5, self.__set_bit(data, BIT_BOOT))
		# sleep_ms(10)
		# self.__write_mem(REG_CTRL_REG5, self.__cls_bit(data, BIT_BOOT))


	def block_data_update_enabled(self, enabled:bool):
		'''
		启用/禁用块数据更新功能
		- 启用：数据块读取后更新
		- 禁用：数据块持续更新
		'''
		data = self.__set_mode(self.__read_mem(REG_CTRL_REG4)[0], BIT_BDU, enabled)
		self.__write_mem(REG_CTRL_REG4, data)

	def full_scale(self, scale:int):
		'''设置满量程数值'''
		data = self.__set_bits(self.__read_mem(REG_CTRL_REG4)[0], BIT_FS0, scale, 2)
		self.__write_mem(REG_CTRL_REG4, data)

	def operating_mode(self, mode:int):
		'''设置/获取操作模式'''
		data1 = self.__read_mem(REG_CTRL_REG1)[0]
		data2 = self.__read_mem(REG_CTRL_REG4)[0]

		if mode == LIS2DH12Lite.MODE_HIGH_RES_12BIT:
			self.__cls_bit(data1, BIT_LPEN)
			self.__set_bit(data2, BIT_HR)
		elif mode == LIS2DH12Lite.MODE_NORMAL_10BIT:
			self.__cls_bit(data1, BIT_LPEN)
			self.__cls_bit(data2, BIT_HR)
		elif mode == LIS2DH12Lite.MODE_LOW_POWER_8BIT:
			self.__set_bit(data1, BIT_LPEN)
			self.__cls_bit(data2, BIT_HR)

		self.__write_mem(REG_CTRL_REG1, data1)
		self.__write_mem(REG_CTRL_REG4, data2)

	def data_rate(self, power_mode:int):
		'''设置/获取输出数据速率'''
		if power_mode not in LIS2DH12Lite.ORD_RANGES:
			power_mode = LIS2DH12Lite.ORD_POWER_DOWN

		data = self.__set_bits(self.__read_mem(REG_CTRL_REG1)[0], BIT_ORD0, power_mode, 4)
		self.__write_mem(REG_CTRL_REG1, data)

	def click_config(self, mode:int):
		data = PROPERTY_DISABLED

		if mode == LIS2DH12Lite.MODE_CLICK_SINGLE:
			data = SINGLE_CLICK
		elif mode == LIS2DH12Lite.MODE_CLICK_DOUBLE:
			data = DOUBLE_CLICK

		self.__write_mem(REG_CLICK_CFG, data)

	def click_source(self):
		'''
		@return: [x, y, z, sign, sclick, dclick, ia]
		'''
		data = self.__read_mem(REG_CLICK_SRC)[0]
		return tuple(reversed([int(i) for i in f'{data:08b}'][1:]))

	def int1_config(self, mode:int):
		data = PROPERTY_DISABLED

		if mode == LIS2DH12Lite.MODE_6D_MOVEMENT:
			data = MOVEMENT_6D
		elif mode == LIS2DH12Lite.MODE_6D_DIRECTION:
			data = DIRECTION_6D

		self.__write_mem(REG_INT1_CFG, data)

	def int2_config(self, mode:int):
		data = PROPERTY_DISABLED

		if mode == LIS2DH12Lite.MODE_6D_MOVEMENT:
			data = MOVEMENT_6D
		elif mode == LIS2DH12Lite.MODE_6D_DIRECTION:
			data = DIRECTION_6D

		self.__write_mem(REG_INT2_CFG, data)

	def int1_source(self):
		'''
		@return: [xl, xh, yl, yh, zl, zh, ia]
		'''
		data = self.__read_mem(REG_INT1_SRC)[0]
		return data
		# return tuple(reversed([int(i) for i in f'{data:08b}'][1:]))

	def int2_source(self):
		'''
		@return: [xl, xh, yl, yh, zl, zh, ia]
		'''
		data = self.__read_mem(REG_INT2_SRC)[0]
		return data
		# return tuple(reversed([int(i) for i in f'{data:08b}'][1:]))


	#region class properties
	@property
	def click_threshold(self):
		return self.__read_mem(REG_CLICK_THS)[0] & 0x7f # 0b0111 1111

	@click_threshold.setter
	def click_threshold(self, value:int):
		data = self.__read_mem(REG_CLICK_THS)[0]
		data = self.__set_bits(data, BIT_THS0, value, 7) # ths0 ~ ths6
		self.__write_mem(REG_CLICK_THS, data)

	@property
	def click_time_limit(self):
		return self.__read_mem(REG_TIME_LIMIT)[0] & 0x7f # 0b0111 1111

	@click_time_limit.setter
	def click_time_limit(self, value:int):
		data = self.__read_mem(REG_TIME_LIMIT)[0]
		data = self.__set_bits(data, BIT_TLI0, value, 7) # tli0 ~ tli6
		self.__write_mem(REG_TIME_LIMIT, data)

	@property
	def click_time_latency(self):
		return self.__read_mem(REG_TIME_LATENCY)[0] & 0xff # 0b1111 1111

	@click_time_latency.setter
	def click_time_latency(self, value:int):
		self.__write_mem(REG_TIME_LATENCY, value)

	@property
	def click_time_window(self):
		return self.__read_mem(REG_TIME_WINDOW)[0] & 0xff # 0b1111 1111

	@click_time_window.setter
	def click_time_window(self, value:int):
		self.__write_mem(REG_TIME_WINDOW, value)

	@property
	def int1_click_enabled(self):
		return True if self.__get_bit(self.__read_mem(REG_CTRL_REG3)[0], BIT_I1_CLICK) else False

	@int1_click_enabled.setter
	def int1_click_enabled(self, enabled:bool):
		data = self.__set_mode(self.__read_mem(REG_CTRL_REG3)[0], BIT_I1_CLICK, enabled)
		# data = self.__set_mode(self.__read_mem(REG_CTRL_REG3)[0], BIT_I1_IA1, enabled)
		self.__write_mem(REG_CTRL_REG3, data)

	@property
	def int2_click_enabled(self):
		return True if self.__get_bit(self.__read_mem(REG_CTRL_REG6)[0], BIT_I2_CLICK) else False

	@int2_click_enabled.setter
	def int2_click_enabled(self, enabled:bool):
		data = self.__set_mode(self.__read_mem(REG_CTRL_REG6)[0], BIT_I2_CLICK, enabled)
		# data = self.__set_mode(self.__read_mem(REG_CTRL_REG6)[0], BIT_I2_IA2, enabled)
		self.__write_mem(REG_CTRL_REG6, data)

	@property
	def int1_duration(self):
		return self.__read_mem(REG_INT1_DUR)[0] & 0x7f # 0b0111 1111

	@int1_duration.setter
	def int1_duration(self, value:int):
		data = self.__read_mem(REG_INT1_DUR)[0]
		data = self.__set_bits(data, BIT_D0, value, 7) # d0 ~ d6
		self.__write_mem(REG_INT1_DUR, data)

	@property
	def int2_duration(self):
		return self.__read_mem(REG_INT2_DUR)[0] & 0x7f # 0b0111 1111

	@int2_duration.setter
	def int2_duration(self, value:int):
		data = self.__read_mem(REG_INT2_DUR)[0]
		data = self.__set_bits(data, BIT_D0, value, 7) # d0 ~ d6
		self.__write_mem(REG_INT2_DUR, data)

	@property
	def int1_threshold(self):
		return self.__read_mem(REG_INT1_THS)[0] & 0x7f # 0b0111 1111

	@int1_threshold.setter
	def int1_threshold(self, value:int):
		# 1 LSb = 16 mg @ FS = 2 g, 32 mg @ FS = 4 g, 62 mg @ FS = 8 g, 186 mg @ FS = 16 g
		data = self.__read_mem(REG_INT1_THS)[0]
		data = self.__set_bits(data, BIT_THS0, value, 7) # ths0 ~ ths6
		self.__write_mem(REG_INT1_THS, data)

	@property
	def int2_threshold(self):
		return self.__read_mem(REG_INT2_THS)[0] & 0x7f # 0b0111 1111

	@int2_threshold.setter
	def int2_threshold(self, value:int):
		data = self.__read_mem(REG_INT2_THS)[0]
		data = self.__set_bits(data, BIT_THS0, value, 7) # ths0 ~ ths6
		self.__write_mem(REG_INT2_THS, data)
	#endregion class properties


	#region tools function
	def __set_bit(self, data:int, index:int):
		'''字节指定位置 1'''
		return data | (1 << index)

	def __get_bit(self, data:int, index:int):
		'''获取字节指定位数据'''
		return (data >> index) & 0x1

	def __cls_bit(self, data:int, index:int):
		'''字节指定位置 0'''
		return data & ~(1 << index)

	def __set_bits(self, data:int, start:int, value:int, length:int):
		'''设置字节多位位数据'''
		v1 = value << start
		v2 = data & (0xff >> (8 - start))
		v3 = data >> (start + length) << (start + length)

		return v3 | v2 | v1

	def __get_bits(self, data:int, start:int, length:int):
		'''获取字节多位位数据'''
		return (data >> start) & (0xff >> (8 - length))

	def __set_mode(self, data:int, index:int, mode):
		'''设置字节指定位置 0 或 置 1'''
		return self.__set_bit(data, index) if mode else self.__cls_bit(data, index)

	def __write_mem(self, mem_addr:int, data):
		'''向指定的寄存器写入数据'''
		if isinstance(data, int):
			data = [data]

		self.__i2c.writeto_mem(self.__i2c_addr, mem_addr, bytearray(data))

	def __read_mem(self, mem_addr:int, nbytes=1):
		'''从指定的寄存器读取数据'''
		if nbytes > 1:
			mem_addr |= 0x80

		return bytearray(self.__i2c.readfrom_mem(self.__i2c_addr, mem_addr, nbytes))
	#endregion tools function


	#region dummy
	_ = 0
	#endregion dummy

count_1 = 0
def int1_double_click_callback(pin):
	global count_1
	count_1 += 1
	print(f'[{count_1}]double clicked')

count_2 = 0
def int2_single_click_callback(pin):
	global count_2
	count_2 += 1
	print(f'[{count_2}]single clicked')

count_3 = 0
def int2_direction_callback(pin):
	global count_3
	count_3 += 1
	print(f'[{count_3}]device rotated')

count_4 = 0
count_5 = 0
def int1_double_click_and_orientation(pin):
	global count_4
	count_4 += 1
	print(f'[{count_4}]double clicked')

def int2_orientation_and_double_click(pin):
	global count_5
	count_5 += 1
	print(f'[{count_5}]device rotated')

def test_double_click_and_orientation(lis2dh12:LIS2DH12Lite, show_log):
	lis2dh12.click_threshold = 0x12
	lis2dh12.click_time_limit = 0x20
	lis2dh12.click_time_latency = 0x20
	lis2dh12.click_time_window = 0x20
	lis2dh12.int1_click_enabled = True
	lis2dh12.int1_duration = 0x00
	lis2dh12.click_config(LIS2DH12Lite.MODE_CLICK_DOUBLE)

	int1_pin = Pin(10, Pin.IN, Pin.PULL_UP)
	int1_pin.irq(int1_double_click_and_orientation, trigger=Pin.IRQ_RISING)


	# lis2dh12.data_rate(LIS2DH12Lite.ORD_25HZ)
	# lis2dh12.full_scale(LIS2DH12Lite.FULL_SCALE_2G)

	lis2dh12.int2_threshold = 0x20
	# lis2dh12.int2_click_enabled = True
	lis2dh12.int2_duration = 0x00
	lis2dh12.int2_config(LIS2DH12Lite.MODE_6D_DIRECTION)

	lis2dh12.full_scale(LIS2DH12Lite.FULL_SCALE_2G)
	lis2dh12.operating_mode(LIS2DH12Lite.MODE_NORMAL_10BIT)
	lis2dh12.data_rate(LIS2DH12Lite.ORD_400HZ)
	lis2dh12.block_data_update_enabled(True)


	direction = last_direction = 0
	while True:
		source = lis2dh12.int2_source()
		direction = source & 0x3f

		if last_direction != direction:
			if direction == 0x01:
				print(f'direction XL')
			elif direction == 0x02:
				print(f'direction XH')
			elif direction == 0x04:
				print(f'direction YL')
			elif direction == 0x08:
				print(f'direction YH')
			elif direction == 0x10:
				print(f'direction ZL')
			elif direction == 0x20:
				print(f'direction ZH')
			else:
				sleep_ms(100)
				continue

			last_direction = direction

		source = lis2dh12.int2_source()
		sleep_ms(100)

def test_orientation(lis2hd12:LIS2DH12Lite, show_log:bool=True):
	lis2dh12.data_rate(LIS2DH12Lite.ORD_25HZ)
	lis2dh12.full_scale(LIS2DH12Lite.FULL_SCALE_2G)
	lis2dh12.int2_threshold = 0x12
	# lis2dh12.int2_click_enabled = True
	lis2dh12.int2_duration = 0x00
	lis2dh12.int2_config(LIS2DH12Lite.MODE_6D_DIRECTION)
	lis2dh12.operating_mode(LIS2DH12Lite.MODE_NORMAL_10BIT)

	int1_pin = Pin(10, Pin.IN, Pin.PULL_UP)
	int1_pin.irq(int2_direction_callback, trigger=Pin.IRQ_RISING)

	# last_direction = 0
	# while True:
	# 	source = lis2dh12.int2_source()
	# 	direction = source & 0x3f

	# 	if last_direction != direction:
	# 		if direction == 0x01:
	# 			print(f'direction XL')
	# 		elif direction == 0x02:
	# 			print(f'direction XH')
	# 		elif direction == 0x04:
	# 			print(f'direction YL')
	# 		elif direction == 0x08:
	# 			print(f'direction YH')
	# 		elif direction == 0x10:
	# 			print(f'direction ZL')
	# 		elif direction == 0x20:
	# 			print(f'direction ZH')

	# 		last_direction = direction

	# 	sleep_ms(20)

def test_single_click(lis2dh12:LIS2DH12Lite, show_log:bool=True):
	# 如果所选通道上的输入加速度超过设定的阈值、并且
	# 在由 TIME_LIMIT 寄存器定义的时窗内恢复至阈值以下，则会生成中断

	lis2dh12.data_rate(LIS2DH12Lite.ORD_400HZ)
	lis2dh12.full_scale(LIS2DH12Lite.FULL_SCALE_2G)
	lis2dh12.click_threshold = 0x12
	lis2dh12.click_time_limit = 0x20
	lis2dh12.int2_click_enabled = True
	lis2dh12.int2_duration = 0x00
	lis2dh12.click_config(LIS2DH12Lite.MODE_CLICK_SINGLE)
	lis2dh12.operating_mode(LIS2DH12Lite.MODE_NORMAL_10BIT)

	int2_pin = Pin(20, Pin.IN, Pin.PULL_UP)
	int2_pin.irq(int2_single_click_callback, trigger=Pin.IRQ_FALLING)
	lis2dh12.click_source()

	# count = 0
	# while True:
	# 	source = lis2dh12.click_source()

	# 	if source[BIT_SCLICK]:
	# 		count += 1
	# 		print(f'[{count}]single clicked (x={source[BIT_CLICK_X]}, y={source[BIT_CLICK_Y]}, z={source[BIT_CLICK_Z]}, sign={source[BIT_SIGN]})')

	# 	sleep_ms(20)

def test_double_click(lis2dh12:LIS2DH12Lite, show_log:bool=True):
	'''
	Set click threshold to 12h -> 0.281 g
	* 1 LSB = full scale/128
	*
	* Set TIME_LIMIT to 20h -> 80 ms
	* Set TIME_LATENCY to 20h -> 80 ms
	* Set TIME_WINDOW to 30h -> 120 ms
	* 1 LSB = 1/ODR
	'''
	lis2dh12.full_scale(LIS2DH12Lite.FULL_SCALE_2G)

	lis2dh12.click_threshold = 0x12
	if show_log: print(f'click threshold: {lis2dh12.click_threshold}')

	lis2dh12.click_time_limit = 0x20
	if show_log: print(f'click time limit: {lis2dh12.click_time_limit}')

	lis2dh12.click_time_latency = 0x20
	if show_log: print(f'click time latency: {lis2dh12.click_time_latency}')

	lis2dh12.click_time_window = 0x20
	if show_log: print(f'click time window: {lis2dh12.click_time_window}')

	lis2dh12.int1_click_enabled = True
	if show_log: print(f'click interrupt on int1: {lis2dh12.int1_click_enabled}')

	lis2dh12.int1_duration = 0x00
	if show_log: print(f'int1 min duration: {lis2dh12.int1_duration}')

	lis2dh12.click_config(LIS2DH12Lite.MODE_CLICK_DOUBLE)

	# Set device in HR mode
	lis2dh12.operating_mode(LIS2DH12Lite.MODE_NORMAL_10BIT)

	# double-click recognition is 400 Hz or higher
	lis2dh12.data_rate(LIS2DH12Lite.ORD_400HZ)

	lis2dh12.block_data_update_enabled(False)

	int1_pin = Pin(10, Pin.IN, Pin.PULL_UP)
	int1_pin.irq(int1_double_click_callback, trigger=Pin.IRQ_RISING)

	# count = 0
	# while True:
	# 	source = lis2dh12.click_source()

	# 	if source[BIT_DCLICK]:
	# 		count += 1
	# 		print(f'[{count}]double clicked (x={source[BIT_CLICK_X]}, y={source[BIT_CLICK_Y]}, z={source[BIT_CLICK_Z]}, sign={source[BIT_SIGN]})')

	# 	sleep_ms(20)


if __name__ == '__main__':
	sleep_ms(10) # sensor boot time

	i2c = SoftI2C(scl=Pin(3), sda=Pin(2))
	print(f'scanned iic device: {i2c.scan()}')

	lis2dh12 = LIS2DH12Lite(i2c, 0x19)

	if lis2dh12.device_id() != LIS2DH12Lite.ID:
		print('invalid lis2dh12 device id')
		exit(0)

	show_log = True
	lis2dh12.reset()

	# test_double_click(lis2dh12, show_log)
	# test_single_click(lis2dh12, show_log)
	# test_orientation(lis2dh12, show_log)
	test_double_click_and_orientation(lis2dh12, show_log)
